package rexsee.location;

import java.io.IOException;
import java.util.List;

import rexsee.core.browser.Browser;
import rexsee.core.browser.clazz.ActivityResult.ActivityResultListener;
import rexsee.core.browser.clazz.JavascriptInterface;
import rexsee.core.utilities.Utilities;
import android.content.Context;
import android.content.Intent;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.provider.Settings;

public class RexseeGps implements JavascriptInterface {

	public static final String INTERFACE_NAME = "Gps";
	@Override
	public String getInterfaceName() {
		return mBrowser.application.resources.prefix + INTERFACE_NAME;
	}
	@Override
	public JavascriptInterface getInheritInterface(Browser childBrowser) {
		return this;
	}
	@Override
	public JavascriptInterface getNewInterface(Browser childBrowser) {
		return new RexseeGps(childBrowser);
	}

	public static final String EVENT_ONGPSSETTINGSUCCESSED = "onGpsSettingSuccessed";
	public static final String EVENT_ONGPSSETTINGFAILED = "onGpsSettingFailed";
	public static final String EVENT_ONGPSENABLED = "onGpsEnabled";
	public static final String EVENT_ONGPSDISABLED = "onGpsDisabled";
	public static final String EVENT_ONGPSSTATUSCHANGED = "onGpsStatusChanged";
	public static final String EVENT_ONGPSLOCATIONCHANGED = "onGpsLocationChanged";

	public static String address2Json(Address address) {
		if (address == null) return "{}";
		String rtn = "";
		rtn += "{";
		rtn += "\"Premises\":\"" + address.getPremises() + "\""; //Type of the location. Cross, road or POI.
		rtn += ",\"Latitude\":" + address.getLatitude();
		rtn += ",\"Longitude\":" + address.getLongitude();
		rtn += ",\"address\":[";
		for (int j = 0; j < address.getMaxAddressLineIndex(); j++) {
			if (j != 0) rtn += ",";
			rtn += "\"" + address.getAddressLine(j) + "\"";
		}
		rtn += "]";
		rtn += ",\"CountyCode\":\"" + address.getCountryCode() + "\"";
		rtn += ",\"CountryName\":\"" + address.getCountryName() + "\"";
		rtn += ",\"AdminArea\":\"" + address.getAdminArea() + "\"";
		rtn += ",\"SubAdminArea\":\"" + address.getSubAdminArea() + "\"";
		rtn += ",\"Locality\":\"" + address.getLocality() + "\"";
		//rtn += ",\"SubLocality\":\"" + address.getSubLocality() + "\"";Not support SDK3
		rtn += ",\"Thoroughfare\":\"" + address.getThoroughfare() + "\"";
		//rtn += ",\"SubThoroughfare\":\"" + address.getSubThoroughfare() + "\"";Not support SDK3
		rtn += ",\"PostalCode\":\"" + address.getPostalCode() + "\"";
		rtn += ",\"FeatureName\":\"" + address.getFeatureName() + "\"";
		rtn += ",\"Phone\":\"" + address.getPhone() + "\"";
		//rtn += ",\"Premises\":\"" + address.getPremises() + "\"";Not support SDK3
		rtn += ",\"Url\":\"" + address.getUrl() + "\"";
		rtn += ",\"Language\":\"" + address.getLocale().getDisplayLanguage() + "\"";
		rtn += "}";
		return rtn;
	}
	public static String addresses2Json(List<Address> addresses) {
		String rtn = "[";
		for (int i = 0; i < addresses.size(); i++) {
			if (i != 0) rtn += ",";
			rtn += address2Json(addresses.get(0));
		}
		rtn += "]";
		return rtn;
	}

	private int minUpdateDuration = 60;
	private int minUpdateDistance = 500;

	private final Context mContext;
	private final Browser mBrowser;

	private final LocationListener mListener;

	public RexseeGps(final Browser browser) {
		mContext = browser.getContext();
		mBrowser = browser;
		browser.eventList.add(EVENT_ONGPSSETTINGSUCCESSED);
		browser.eventList.add(EVENT_ONGPSSETTINGFAILED);
		browser.eventList.add(EVENT_ONGPSENABLED);
		browser.eventList.add(EVENT_ONGPSDISABLED);
		browser.eventList.add(EVENT_ONGPSSTATUSCHANGED);
		browser.eventList.add(EVENT_ONGPSLOCATIONCHANGED);
		browser.destroyListeners.add(new Runnable() {
			@Override
			public void run() {
				stop();
			}
		});
		mListener = new LocationListener() {
			@Override
			public void onLocationChanged(Location location) {
				if (browser != null) {
					browser.eventList.run(EVENT_ONGPSLOCATIONCHANGED, new String[]{
								String.valueOf(location.getTime()),
								String.valueOf(location.getAccuracy()),
								String.valueOf(location.getLongitude()),
								String.valueOf(location.getLatitude()),
								String.valueOf(location.getSpeed()),
								String.valueOf(location.getBearing()),
								String.valueOf(location.getAltitude())
						});
				}
			}
			@Override
			public void onProviderDisabled(String provider) {
				if (browser != null) {
					browser.eventList.run(EVENT_ONGPSDISABLED);
				}
			}
			@Override
			public void onProviderEnabled(String provider) {
				if (browser != null) {
					browser.eventList.run(EVENT_ONGPSENABLED);
				}
			}
			@Override
			public void onStatusChanged(String provider, int status, Bundle extras) {
				if (browser != null) {
					browser.eventList.run(EVENT_ONGPSSTATUSCHANGED, new String[]{String.valueOf(status)});
				}
			}
		};
	}

	//JavaScript Interface
	public boolean isReady() {
		try {
			return (((LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE)).isProviderEnabled(LocationManager.GPS_PROVIDER)) ? true : false;
		} catch (Exception e) {
			mBrowser.exception(getInterfaceName(), e);
			return false;
		}
	}
	public void openSettings() {
		Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
		mBrowser.activityResult.start(intent, new ActivityResultListener() {
			@Override
			public void run(int resultCode, Intent resultIntent) {
				if (isReady()) {
					mBrowser.eventList.run(EVENT_ONGPSSETTINGSUCCESSED);
				} else {
					mBrowser.eventList.run(EVENT_ONGPSSETTINGFAILED);
				}
			}
		});
	}
	public void start() {
		if (isReady()) {
			LocationManager locationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
			locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, minUpdateDuration * 1000, minUpdateDistance, mListener);
		} else {
			mBrowser.exception(getInterfaceName(), "GPS is not available.");
		}
	}
	public void stop() {
		try {
			((LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE)).removeUpdates(mListener);
		} catch (Exception e) {
		}
	}

	public void setMinimumUpdateDuration(int seconds) {
		minUpdateDuration = seconds;
	}
	public int getMinimumUpdateDuration() {
		return minUpdateDuration;
	}
	public void setMinimumUpdateDistance(int meter) {
		minUpdateDistance = meter;
	}
	public int getMinimumUpdateDistance() {
		return minUpdateDistance;
	}

	public String getLastKnownLocation() {
		if (!isReady()) return "{}";
		try {
			Location location = ((LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE)).getLastKnownLocation(LocationManager.GPS_PROVIDER);
			if (location == null) return "";
			String rtn = "{";
			rtn += "\"time\":" + location.getTime();
			rtn += ",\"accuracy\":" + location.getAccuracy();
			rtn += ",\"longitude\":" + location.getLongitude();
			rtn += ",\"latitude\":" + location.getLatitude();
			rtn += ",\"speed\":" + location.getSpeed();
			rtn += ",\"bearing\":" + location.getBearing();
			rtn += ",\"altitude\":" + location.getAltitude();
			rtn += "}";
			return rtn;
		} catch (Exception e) {
			mBrowser.exception(getInterfaceName(), e);
			return "{}";
		}
	}
	public String getLastKnownGeo(int maxNumber) {
		if (!isReady()) return "[]";
		try {
			Location location = ((LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE)).getLastKnownLocation(LocationManager.GPS_PROVIDER);
			if (location == null) return "";
			Geocoder geo = new Geocoder(mContext);
			List<Address> addresses = geo.getFromLocation(location.getLatitude(), location.getLongitude(), maxNumber);
			return addresses2Json(addresses);
		} catch (IOException e) {
			mBrowser.exception(getInterfaceName(), e);
			return "[]";
		}
	}

	public float getDistanceBetween(String startLongitude, String startLatitude, String endLongitude, String endLatitude) {
		double sLatitude = Utilities.getDouble(startLatitude, 0);
		double sLongitude = Utilities.getDouble(startLongitude, 0);
		double eLatitude = Utilities.getDouble(endLatitude, 0);
		double eLongitude = Utilities.getDouble(endLongitude, 0);
		float results[] = new float[3];
		Location.distanceBetween(sLatitude, sLongitude, eLatitude, eLongitude, results);
		return results[0];
	}

}
